package com.dl.dlcommon.utils;

import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.EncryptionMethod;

import java.io.*;
import java.nio.file.Files;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author DL
 * @create 2024-01-18 10:49
 */
public class ZipUtil {

    // 用于跟踪已处理的目录
    private static final Set<String> PROCESSED_DIRECTORIES = new HashSet<>();


    public static void main(String[] args) {
        String sourceFolder = "D:\\DL\\Project\\my-test\\test\\src\\main\\resources\\xml\\";
        String zipFilePath = "D:\\DL\\Project\\my-test\\test\\src\\main\\resources\\xml\\";

        try {
            zipFolder(sourceFolder, zipFilePath, "export.zip");
            System.out.println("Compression completed.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 压缩文件夹
     * @param sourceFolderPath 源文件夹路径
     * @param zipFolderPath  压缩文件存放路径
     * @param zipFileName 压缩文件名称
     * @throws IOException
     */
    public static void zipFolder(String sourceFolderPath, String zipFolderPath, String zipFileName) throws IOException {
        zipFolderPath = FileUtil.concatPathName(zipFolderPath, zipFileName);

        try (
                FileOutputStream fos = new FileOutputStream(zipFolderPath);
                ZipOutputStream zipOut = new ZipOutputStream(fos)
        ) {
            PROCESSED_DIRECTORIES.clear(); // 清空已处理目录的记录
            PROCESSED_DIRECTORIES.add(zipFolderPath);
            File fileToZip = new File(sourceFolderPath);
            zipFile(fileToZip, "", zipOut);
        }
    }

    /**
     *  递归压缩文件夹
     * @param fileToZip 文件
     * @param parentPath 父级路径
     * @param zipOut 压缩流
     * @throws IOException
     */
    private static void zipFile(File fileToZip, String parentPath, ZipOutputStream zipOut) throws IOException {
        if (fileToZip.isHidden()) {
            return;
        }
        // 检查目录是否已处理
        if (!PROCESSED_DIRECTORIES.add(fileToZip.getAbsolutePath())) {
            // 如果已处理，跳过
            return;
        }
        if (fileToZip.isDirectory()) {
            File[] children = fileToZip.listFiles();
            if (children != null) {
                for (File childFile : children) {
                    // 修改这里，将 parentPath 设为空字符串
                    zipFile(childFile, "", zipOut);
                }
            }
        } else {
            try (
                    FileInputStream fis = new FileInputStream(fileToZip)
            ) {
                ZipEntry zipEntry = new ZipEntry(parentPath + fileToZip.getName());
                zipOut.putNextEntry(zipEntry);

                // 读取文件内容并写入ZIP输出流
                byte[] bytes = new byte[1024];
                int length;
                while ((length = fis.read(bytes)) >= 0) {
                    zipOut.write(bytes, 0, length);
                }
            }
        }
    }

    public static byte[] createInMemoryZip(String... entries) throws Exception {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ZipOutputStream zos = new ZipOutputStream(baos)) {

            for (int i = 0; i < entries.length; i += 2) {
                String fileName = entries[i];
                String fileContent = entries[i + 1];

                // 将文件写入 ZIP 中
                zos.putNextEntry(new ZipEntry(fileName));
                zos.write(fileContent.getBytes());
                zos.closeEntry();
            }

            zos.finish();
            zos.flush();

            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            throw new Exception();
        }
    }

    public static byte[] createInMemoryZip(List<Map<String,String>> contentList) throws Exception {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ZipOutputStream zos = new ZipOutputStream(baos)) {

            for (Map<String, String> map : contentList) {
                String fileName = map.get("fileName");
                String fileContent = map.get("fileContent");

                // 将文件写入 ZIP 中
                zos.putNextEntry(new ZipEntry(fileName));
                zos.write(fileContent.getBytes());
                zos.closeEntry();
            }

            zos.finish();
            zos.flush();

            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            throw new Exception();
        }
    }

}
